﻿namespace SuperModel
{
    using System;
    using System.ComponentModel;
    using Generation;

    /// <summary>
    /// The Super-Model Factory
    /// </summary>        
    /// <TODO>
    /// 1) Allow class-based model creation through abstract properties ala bl-toolkit.
    /// 2) More customizable behavior via attributes (e.g. NotifyOnAllSets)
    /// 3) Test and support serialization via xml or data contract attributes.
    /// 4) Support default values via attributes in the Component Model
    /// </TODO>
    public class SuperModelFactory
    {
        /// <summary>
        /// The model proxy generator
        /// </summary>
        private readonly ModelProxier modelProxier = new ModelProxier();

        /// <summary>
        /// The Auto-Generated Implementation Cache
        /// </summary>
        private readonly ImplementationCache implementationCache = new ImplementationCache();

        /// <summary>
        /// Create a Super-Model
        /// </summary>
        /// <typeparam name="T">
        /// The type to create
        /// </typeparam>
        /// <returns>
        /// An instance of the created type
        /// </returns>
        public T Create<T>()
            where T : INotifyPropertyChanged
        {
            var type = implementationCache.CreateImplementationType<T>();
            return (T)Create(type);
        }

        /// <summary>
        /// Creates a Super-Model
        /// </summary>
        /// <param name="args">
        /// The constructor args of the target type.
        /// </param>
        /// <typeparam name="T">
        /// The type to create.
        /// </typeparam>
        /// <returns>
        /// An instance of the created type.
        /// </returns>
        public T Create<T>(params object[] args)
            where T : class, INotifyPropertyChanged
        {
            return (T)Create(typeof(T), args);
        }

        /// <summary>
        /// Builds an Instance of a Type
        /// </summary>
        /// <param name="typeToBuild">
        /// The type to build.
        /// </param>
        /// <param name="args">
        /// The constructor args.
        /// </param>
        /// <returns>
        /// The built type
        /// </returns>
        public object Create(Type typeToBuild, params object[] args)
        {
            return modelProxier.ProxyNewInstanceOf(typeToBuild, args);
        }
    }
}